Split array into Fibonacci sequence [Brute Force]

Time: O(N^3); Space: O(N); medium

Given a string S of digits, such as S = ‘123456579’, we can split it into a Fibonacci-like sequence [123, 456, 579].

Formally, a Fibonacci-like sequence is a list F of non-negative integers such that: 0 <= F[i] <= 2^31 - 1, (that is, each integer fits a 32-bit signed integer type); F.length >= 3; and F[i] + F[i+1] = F[i+2] for all 0 <= i < F.length - 2.

Also, note that when splitting the string into pieces, each piece must not have extra leading zeroes, except if the piece is the number 0 itself.

Return any Fibonacci-like sequence split from S, or return [] if it cannot be done.

Example 1:

Input: S = ‘123456579’

Output: [123,456,579]

Example 2:

Input: S = ‘11235813’

Output: [1,1,2,3,5,8,13]

Example 3:

Input: S = ‘112358130’

Output: []

Explanation:

  • The task is impossible.

Example 4:

Input: S = ‘0123’

Output: []

Explanation:

  • Leading zeroes are not allowed

Example 5:

Input: S = ‘1101111’

Output: [110, 1, 111]

Explanation:

  • The output [11, 0, 11, 11] would also be accepted.

Constraints:

  • 1 <= len(S) <= 200

  • S contains only digits.

1. Brute Force

Intuition

The first two elements of the array uniquely determine the rest of the sequence.

Algorithm

For each of the first two elements, assuming they have no leading zero, let’s iterate through the rest of the string. At each stage, we expect a number less than or equal to 2^31 - 1 that starts with the sum of the two previous numbers.

[6]:
class Solution1(object):
    def splitIntoFibonacci(self, S):
        """
        :type S: str
        :rtype: List[int]
        """
        for i in range(min(10, len(S))):
            x = S[:i + 1]
            if x != '0' and x.startswith('0'):
                break
            a = int(x)
            for j in range(i + 1, min(i + 10, len(S))):
                y = S[i + 1: j + 1]
                if y != '0' and y.startswith('0'):
                    break
                b = int(y)
                fib = [a, b]
                k = j + 1
                while k < len(S):
                    nxt = fib[-1] + fib[-2]
                    nxtS = str(nxt)
                    if nxt <= 2**31 - 1 and S[k:].startswith(nxtS):
                        k += len(nxtS)
                        fib.append(nxt)
                    else:
                        break
                else:
                    if len(fib) >= 3:
                        return fib
        return []
[7]:
s = Solution1()
S = '123456579'
assert s.splitIntoFibonacci(S) == [123,456,579]
S = '11235813'
assert s.splitIntoFibonacci(S) == [1,1,2,3,5,8,13]
S = '112358130'
assert s.splitIntoFibonacci(S) ==  []
S = '0123'
assert s.splitIntoFibonacci(S) == []
S = '1101111'
assert s.splitIntoFibonacci(S) == [110, 1, 111] or [11, 0, 11, 11]
[8]:
class Solution2(object):
    def splitIntoFibonacci(self, S):
        """
        :type S: str
        :rtype: List[int]
        """
        def startsWith(S, k, x):
            y = 0
            for i in range(k, len(S)):
                y = 10* y + int(S[i])
                if y == x:
                    return i - k + 1
                elif y > x:
                    break
            return 0

        MAX_INT = 2**31-1
        a = 0
        for i in range(len(S)-2):
            a = 10 * a + int(S[i])
            b = 0
            for j in range(i + 1, len(S) - 1):
                b = 10 * b + int(S[j])
                fib = [a, b]
                k = j + 1
                while k < len(S):
                    if fib[-2] > MAX_INT-fib[-1]:
                        break
                    c = fib[-2] + fib[-1]
                    length = startsWith(S, k, c)
                    if length == 0:
                        break
                    fib.append(c)
                    k += length
                else:
                    return fib
                if b == 0:
                    break
            if a == 0:
                break
        return []
[9]:
s = Solution2()
S = '123456579'
assert s.splitIntoFibonacci(S) == [123,456,579]
S = '11235813'
assert s.splitIntoFibonacci(S) == [1,1,2,3,5,8,13]
S = '112358130'
assert s.splitIntoFibonacci(S) ==  []
S = '0123'
assert s.splitIntoFibonacci(S) == []
S = '1101111'
assert s.splitIntoFibonacci(S) == [110, 1, 111] or [11, 0, 11, 11]